import numpy as np
import pandas as pd
import os
import warnings # 导入warnings模块用于发出警告

# ====================================================================================================
# I. 辅助函数 (Helper Functions)
# ====================================================================================================

def generate_individual_param(pop_mean, cv):
    """
    根据群体均值和变异系数 (CV) 生成一个具有个体间变异的参数，使用对数正态分布。
    对数正态分布确保生物学参数为正值。

    Args:
        pop_mean (float): 群体均值。
        cv (float): 变异系数 (0到1之间的小数，例如 0.2 代表 20%)。
    Returns:
        float: 生成的个体参数值。
    Raises:
        ValueError: 如果CV为负数。
    """
    if cv < 0:
        raise ValueError("CV cannot be negative.")
    if cv == 0:
        return pop_mean # 如果CV为0，则没有变异，直接返回群体均值

    # 对数正态分布要求均值大于0。
    # 对于均值为0但有CV的参数，在对数正态分布中无法直接处理。
    # 此处设定一个极小的正数均值作为基准。
    if pop_mean <= 0:
        warnings.warn(f"For lognormal distribution, pop_mean ({pop_mean}) must be positive. "
                      f"Using a small positive epsilon (1e-6) instead for variation.")
        pop_mean = 1e-6 
    
    # 计算对数正态分布的参数 mu_log 和 sigma_log
    sigma_log = np.sqrt(np.log(1 + cv**2))
    mu_log = np.log(pop_mean) - 0.5 * sigma_log**2
    individual_param = np.exp(np.random.normal(loc=mu_log, scale=sigma_log))

    return individual_param

# ====================================================================================================
# II. 全局配置 (Global Configuration)
# ====================================================================================================

# 集中定义所有需要变异的参数的群体均值和CV。
# 注意：这里定义的CV是小数形式 (e.g., 0.2 for 20%)。
# 根据要求，所有有CV的参数都强制使用 'lognormal' 分布。
POPULATION_PARAMS = {
    # 4. S9 protein, Microsomal protein, Cytosolic protein
    'S9_protein_mg_g': {'mean': 12.8, 'cv': 0.30},
    'Microsomal_protein_mg_g': {'mean': 12.8, 'cv': 0.55},
    # Cytosolic protein: 表格均值为0，但有CV。
    # 为保证对数正态分布的数学有效性，此处设定一个极小的正数均值。
    'Cytosolic_protein_mg_g': {'mean': 0.1, 'cv': 0.30}, 
    
    # 8. Bladder: Proximal Tubule Cells
    'Proximal_Tubule_Cells_Millions_g': {'mean': 99.4, 'cv': 0.33}, 

    # 9. Proportion of Blood Bypass
    'bypass1_percent': {'mean': 10.0, 'cv': 0.30},
    'bypass2_percent': {'mean': 20.0, 'cv': 0.30},
    
    # 10. Parameters for the mechanistic filtration model (Glomerulus)
    # 根据表格，只有血浆渗透压(Mean)有CV。
    'plasma_osmotic_pressure_mmHg': {'mean': 25.8, 'cv': 0.106},
}

# ========================
# Kidney转运体频率数据
# ========================
KIDNEY_TRANSPORTER_FREQUENCIES = {
    'ABCB1 (P-gp)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'ABCC2 (MRP2)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'ABCC4 (MRP4)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'ABCG2 (BCRP)': {'ET': 0.44, 'PT': 0.1, 'IT': 0.46, 'UT': 0.0},
    'SLC10A2 (ASBT)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC16A1 (MCT1)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC19A2 (THTR1)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC19A3 (THTR2)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLCO4C1(OATP4C1)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC22A2 (OCT2)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC22A4 (OCTN1)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC22A5 (OCTN2)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC22A6 (OAT1)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC22A7 (OAT2)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC22A8 (OAT3)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC22A11 (OAT4)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC22A12 (URAT1)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC47A1 (MATE1)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC47A2 (MATE2-K)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0},
    'SLC51A/B (OST-α/β)': {'ET': 1.0, 'PT': 0.0, 'IT': 0.0, 'UT': 0.0}
}

# ========================
# Kidney转运体丰度和周转数据
# ========================
KIDNEY_TRANSPORTER_ABUNDANCES = {
    'ABCB1 (P-gp)': {
        'ET': {'mean': 0.82, 'cv': 74}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 0.054, 'turnover_cv': 28
    },
    'ABCC2 (MRP2)': {
        'ET': {'mean': 0.33, 'cv': 62}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'ABCC4 (MRP4)': {
        'ET': {'mean': 0.27, 'cv': 80}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'ABCG2 (BCRP)': {
        'ET': {'mean': 0.12, 'cv': 59}, 'PT': {'mean': 0.37, 'cv': 59},
        'IT': {'mean': 0.67, 'cv': 59}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC10A2 (ASBT)': {
        'ET': {'mean': 0.0, 'cv': 60}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC16A1 (MCT1)': {
        'ET': {'mean': 0.0, 'cv': 60}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC19A2 (THTR1)': {
        'ET': {'mean': 0.0, 'cv': 60}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC19A3 (THTR2)': {
        'ET': {'mean': 0.0, 'cv': 60}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLCO4C1(OATP4C1)': {
        'ET': {'mean': 0.89, 'cv': 106}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC22A2 (OCT2)': {
        'ET': {'mean': 2.12, 'cv': 66}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC22A4 (OCTN1)': {
        'ET': {'mean': 0.36, 'cv': 68}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC22A5 (OCTN2)': {
        'ET': {'mean': 0.27, 'cv': 121}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC22A6 (OAT1)': {
        'ET': {'mean': 1.55, 'cv': 62}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC22A7 (OAT2)': {
        'ET': {'mean': 0.26, 'cv': 38}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC22A8 (OAT3)': {
        'ET': {'mean': 1.32, 'cv': 85}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC22A11 (OAT4)': {
        'ET': {'mean': 0.21, 'cv': 177}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC22A12 (URAT1)': {
        'ET': {'mean': 13.7, 'cv': 51}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC47A1 (MATE1)': {
        'ET': {'mean': 2.56, 'cv': 107}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC47A2 (MATE2-K)': {
        'ET': {'mean': 0.35, 'cv': 100}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    },
    'SLC51A/B (OST-α/β)': {
        'ET': {'mean': 0.25, 'cv': 53}, 'PT': {'mean': 0.0, 'cv': 0},
        'IT': {'mean': 0.0, 'cv': 0}, 'UT': {'mean': 0.0, 'cv': 0},
        'turnover_mean': 1.00E-06, 'turnover_cv': 30
    }
}

# ====================================================================================================
# III. 肾脏参数计算函数 (Kidney Parameter Calculation Functions)
# 这些函数根据输入的人口学数据和固定/可变参数计算各种肾脏相关的生物学或生理学值。
# 所有带CV的参数都通过 generate_individual_param 使用对数正态分布。
# ====================================================================================================

# --- 1. 血清肌酐 (Serum Creatinine) ---
def calculate_scr_umol_l(age, sex):
    """
    计算血清肌酐 (µmol/L)。根据年龄和性别从预定义表格中抽取参数。
    """
    scr_params = {
        'Male': [
            {'age_cutoff': 65, 'mean': 79.1, 'cv': 15.75}, # <65, 恢复原始CV
            {'age_cutoff': 65, 'mean': 82.01, 'cv': 21.58} # >=65
        ],
        'Female': [
            {'age_cutoff': 45, 'mean': 58.77, 'cv': 18.23}, # <45
            {'age_cutoff': 45, 'mean': 61.14, 'cv': 22.88}, # 45-65
            {'age_cutoff': 65, 'mean': 65.55, 'cv': 25.03}  # >=65
        ]
    }
    
    param = None
    if sex == 'Male':
        param = scr_params['Male'][0] if age < 65 else scr_params['Male'][1]
    else: # Female
        if age < 45:
            param = scr_params['Female'][0]
        elif age < 65:
            param = scr_params['Female'][1]
        else:
            param = scr_params['Female'][2]
            
    mean = param['mean']
    cv_ratio = param['cv'] / 100 # 将百分比CV转换为小数
    
    return generate_individual_param(mean, cv_ratio)

# --- 2. 肾小球滤过率 (GFR Prediction) ---
# 这些是计算值，没有独立CV，直接基于肌酐值计算。
def convert_scr_umol_l_to_mg_dl(scr_umol_l):
    """将血清肌酐从 µmol/L 转换为 mg/dL。"""
    return scr_umol_l / 88.4

def calculate_egfr_cg(age, weight, scr_mg_dl, sex):
    """
    使用 Cockcroft-Gault 公式计算估算肾小球滤过率 (eGFR)。
    
    Args:
        age (float): 年龄(年)
        weight (float): 体重(kg)
        scr_mg_dl (float): 血清肌酐(mg/dL)
        sex (str): 性别 ('Male' 或 'Female')
    Returns:
        float: 估算的肾小球滤过率 (mL/min)
    """
    if scr_mg_dl <= 0: return 0.0 
    
    cg_gfr = (140 - age) * weight / (72 * scr_mg_dl)
    if sex == 'Female':
        cg_gfr *= 0.85
    
    return cg_gfr

def calculate_egfr_mdrd(age, scr_mg_dl, sex):
    """
    使用 MDRD (Modification of Diet in Renal Disease) 公式计算估算肾小球滤过率 (eGFR)。
    
    Args:
        age (float): 年龄(年)
        scr_mg_dl (float): 血清肌酐(mg/dL)
        sex (str): 性别 ('Male' 或 'Female')
    Returns:
        float: 估算的肾小球滤过率 (mL/min)
    """
    if scr_mg_dl <= 0: return 0.0 

    mdrd_gfr = 175 * (scr_mg_dl)**(-1.154) * age**(-0.203)
    if sex == 'Female':
        mdrd_gfr *= 0.742
    
    return mdrd_gfr

# --- 3. 肾脏尺寸 (Kidney Size) ---
def calculate_kidney_volume(weight_kg, height_cm):
    """
    计算肾脏体积 (mL)。基于体重、身高和CV。
    """
    baseline = 15.4 # 固定值
    bw_coefficient = 2.04 # 固定值
    bh_coefficient = 51.8 # 固定值
    cv = 0.224 # CV (22.4% -> 0.224)
    
    height_m = height_cm / 100
    mean_volume = baseline + (bw_coefficient * weight_kg) + (bh_coefficient * height_m)
    
    volume = generate_individual_param(mean_volume, cv)
    return max(0, volume) # 确保体积非负

# --- 4. 肾脏蛋白参数 (Kidney Protein Parameters) ---
def calculate_kidney_protein_parameters():
    """
    计算S9蛋白、微粒体蛋白和细胞质蛋白的浓度。
    这些参数的均值和CV在POPULATION_PARAMS中定义。
    肾脏密度是固定值。
    """
    s9_value = generate_individual_param(POPULATION_PARAMS['S9_protein_mg_g']['mean'],
                                         POPULATION_PARAMS['S9_protein_mg_g']['cv'])
    microsomal_value = generate_individual_param(POPULATION_PARAMS['Microsomal_protein_mg_g']['mean'],
                                                 POPULATION_PARAMS['Microsomal_protein_mg_g']['cv'])
    cytosolic_value = generate_individual_param(POPULATION_PARAMS['Cytosolic_protein_mg_g']['mean'],
                                                POPULATION_PARAMS['Cytosolic_protein_mg_g']['cv'])
    
    kidney_density = 1050.0 # 固定值 (g/L)
    
    return {
        'S9_protein_mg_g': max(0, s9_value),
        'Microsomal_protein_mg_g': max(0, microsomal_value),
        'Cytosolic_protein_mg_g': max(0, cytosolic_value),
        'Kidney_density_g_L': kidney_density
    }

# --- 5. Mech Kim 模型参数 (Permeability-limited kidney model) ---
def calculate_mech_kim_parameters():
    """
    计算 Mech Kim 模型的固定参数。
    这些参数在表格中未给出CV，因此为固定值。
    """
    permeability = 0.1 
    surface_area = 100.0 
    other_param = 1.0 
    cortex_medulla_ratio = 2.56
    peritubular_capillaries_percent = 7.0 # 表格中是7，表示7%
    
    return {
        'permeability': permeability,
        'surface_area': surface_area,
        'other_param': other_param,
        'Cortex_Medulla_Ratio': cortex_medulla_ratio,
        'Peritubular_Capillaries_Percent_Kidney_Volume': peritubular_capillaries_percent
    }

# --- 6. 肾单位数量 (Number of Nephrons) ---
def calculate_kidney_weight(kidney_volume, kidney_density):
    """
    根据肾脏体积和密度计算肾脏重量 (g)。
    """
    kidney_weight_g = kidney_volume * kidney_density / 1000 
    return kidney_weight_g

def calculate_nephron_number(kidney_weight_g, ethnicity='caucasian', age=30):
    """
    计算每名受试者的肾单位数量 (百万个)。
    这些参数在表格中未给出CV，因此为固定计算值。
    """
    baseline = 0.22693 
    coefficient = 0.003948 
    base_nephron_millions = baseline + coefficient * kidney_weight_g
    
    if age > 30:
        age_factor = 1.0 - min(0.5, (age - 30) * 0.007) # 肾单位数量随年龄增长而减少
        base_nephron_millions *= age_factor
        
    ethnicity_factor = 1.0 # 种族修正因子
    if ethnicity.lower() == 'african':
        ethnicity_factor = 0.85
    elif ethnicity.lower() == 'asian':
        ethnicity_factor = 0.9
    
    nephron_millions = base_nephron_millions * ethnicity_factor
    return max(0, nephron_millions) # 确保数量非负

# --- 7. 肾单位几何参数 (Nephron Parameters) ---
def calculate_nephron_dimensions():
    """
    定义肾单位各部分的固定尺寸 (长度和直径)。
    表格中未给出CV，因此所有尺寸参数为固定值。
    """
    return {
        'proximal_tubule': {'length_mm': 18.0, 'diameter_mm': 0.06},
        'henle_loop': {'length_mm': 7.0, 'diameter_mm': 0.018},
        'distal_tubule': {'length_mm': 5.5, 'diameter_mm': 0.05},
        'collecting_duct': {'length_mm': 22.0, 'diameter_mm': 0.2}
    }

def calculate_nephron_volume(dimensions):
    """
    根据肾单位各部分的尺寸计算其体积。
    """
    volumes = {}
    for segment, dims in dimensions.items():
        radius_cm = dims['diameter_mm'] / 2 / 10 # mm to cm
        length_cm = dims['length_mm'] / 10 # mm to cm
        volume_ml = np.pi * (radius_cm ** 2) * length_cm
        volumes[segment] = volume_ml
    volumes['total'] = sum(volumes.values())
    return volumes

# --- 8. 膀胱和近曲小管细胞 (Bladder & Proximal Tubule Cells) ---
def get_bladder_flow():
    """
    获取膀胱流量。表格中未给出CV，沿用固定值。
    """
    return 1.0  # mL/min

def calculate_proximal_tubule_cells():
    """
    计算近曲小管细胞数量。
    """
    cells = generate_individual_param(POPULATION_PARAMS['Proximal_Tubule_Cells_Millions_g']['mean'],
                                      POPULATION_PARAMS['Proximal_Tubule_Cells_Millions_g']['cv'])
    return max(0, cells) # 确保细胞数量非负

# --- 9. 血液分流比例 (Proportion of Blood Bypass) ---
def calculate_blood_bypass_parameters():
    """
    计算血液分流比例。
    """
    bypass1_actual = generate_individual_param(POPULATION_PARAMS['bypass1_percent']['mean'],
                                               POPULATION_PARAMS['bypass1_percent']['cv'])
    bypass2_actual = generate_individual_param(POPULATION_PARAMS['bypass2_percent']['mean'],
                                               POPULATION_PARAMS['bypass2_percent']['cv'])
    # 确保比例在0-100%之间
    return {
        'bypass1_percent': min(max(0, bypass1_actual), 100),
        'bypass2_percent': min(max(0, bypass2_actual), 100)
    }

# --- 10. 肾小球机械过滤模型参数 (Mechanistic Filtration Model for Glomerulus) ---
def calculate_mechanistic_filtration_parameters():
    """
    计算肾小球机械过滤模型的参数。
    根据表格，只有 plasma_osmotic_pressure_mmHg 具有CV。
    """
    # 固定值参数
    jv_s = 0.93021
    jv_l = 0.069785
    alpha_s = 0.94248
    alpha_l = 0.057524
    ns_nl_ratio = 40.0
    r_pore_s = 4.8
    r_pore_l = 6.0
    delta_p = 40.0
    delta_pi = 25.8 # ΔΠ(mmHg) from table
    
    # 具有CV的血浆渗透压
    plasma_osmotic_pressure = generate_individual_param(POPULATION_PARAMS['plasma_osmotic_pressure_mmHg']['mean'],
                                                        POPULATION_PARAMS['plasma_osmotic_pressure_mmHg']['cv'])
    
    # 净过滤压是计算值
    net_filtration_pressure = delta_p - plasma_osmotic_pressure
    
    return {
        'pore_parameters': {
            'r_pore_s_nm': r_pore_s,
            'r_pore_l_nm': r_pore_l,
            'ns_nl_ratio': ns_nl_ratio
        },
        'pressure_parameters': {
            'delta_p_mmHg': delta_p,
            'plasma_osmotic_pressure_mmHg': plasma_osmotic_pressure,
            'delta_pi_mmHg': delta_pi,
            'net_filtration_pressure_mmHg': net_filtration_pressure
        },
        'conductance_fractions': {
            'alpha_s': alpha_s,
            'alpha_l': alpha_l
        },
        'filtration_fractions': {
            'jv_s': jv_s,
            'jv_l': jv_l
        }
    }

# ====================================================================================================
# IV. 主数据生成逻辑 (Main Data Generation Logic)
# ====================================================================================================

def generate_kidney_parameters_from_demographics_csv(
    input_demographics_csv_path, 
    output_csv_path="kidney_parameters_from_demographics.csv", 
    ethnicity='caucasian',
    min_gfr=90,
    max_gfr=400): 
    """
    从指定的包含人口学数据（Age, Weight, Height, Gender等）的CSV文件读取数据，
    然后为每个个体生成肾脏参数，并保存到新的CSV文件。

    Args:
        input_demographics_csv_path (str): 输入人口学CSV文件的完整路径。
        output_csv_path (str): 生成肾脏参数CSV文件的输出路径。
        ethnicity (str): 用于肾单位数量计算的种族信息。如果输入CSV中没有该列，则使用此默认值。
        min_gfr (float): GFR下限 (mL/min)，默认为90 mL/min。
        max_gfr (float): GFR上限 (mL/min)，默认为400 mL/min。
    """
    script_dir = os.path.dirname(os.path.abspath(__file__))
    # 确保输出路径是绝对路径，或者相对于脚本路径
    if not os.path.isabs(output_csv_path):
        output_save_path = os.path.join(script_dir, output_csv_path)
    else:
        output_save_path = output_csv_path

    print(f"正在从 '{input_demographics_csv_path}' 读取人口学数据...")
    try:
        df_demographics = pd.read_csv(input_demographics_csv_path)
    except FileNotFoundError:
        print(f"错误: 找不到文件 '{input_demographics_csv_path}'。请检查路径是否正确。")
        return
    print(f"已读取 {len(df_demographics)} 条人口学记录。")

    processed_data = []
    
    # 预先计算固定值或不随个体变化的参数，以提高效率
    nephron_dimensions = calculate_nephron_dimensions() 
    nephron_volumes = calculate_nephron_volume(nephron_dimensions) 
    
    # 遍历人口学数据的每一行，为每个个体生成肾脏参数
    for index, row_demographics in df_demographics.iterrows():
        # 从人口学数据中提取必要的信息
        # 确保列名与您的CSV文件完全匹配 (ID, Distribution, Gender, Age(years), Height(cm), Weight(kg), BSA (m2))
        person_id = row_demographics.get('ID', index) 
        person_distribution = row_demographics.get('Distribution', '')
        person_gender = row_demographics.get('Gender', 'Male') # 默认性别为Male，如果CSV中没有提供
        person_age = row_demographics.get('Age(years)')
        person_weight = row_demographics.get('Weight(kg)')
        person_height = row_demographics.get('Height(cm)')
        person_bsa = row_demographics.get('BSA (m2)', np.nan) # 如果没有BSA列，则为NaN

        # 检查关键数据是否缺失
        if pd.isna(person_age) or pd.isna(person_weight) or pd.isna(person_height):
            warnings.warn(f"跳过ID为 {person_id} 的个体，因年龄、体重或身高数据缺失。")
            continue

        # --- 生成个体特异性肾脏参数 ---
        # 血清肌酐和GFR计算，确保GFR在指定范围内
        valid_gfr = False
        attempts = 0
        max_attempts = 10  # 最大尝试次数，防止无限循环
        
        while not valid_gfr and attempts < max_attempts:
            # 每次尝试都重新生成血清肌酐值
            scr_umol_l = calculate_scr_umol_l(person_age, person_gender)
            scr_mg_dl = convert_scr_umol_l_to_mg_dl(scr_umol_l)
            
            # 计算GFR
            egfr_cg = calculate_egfr_cg(person_age, person_weight, scr_mg_dl, person_gender)
            # 只用CG公式判断
            if min_gfr <= egfr_cg <= max_gfr:
                valid_gfr = True
            else:
                attempts += 1
        
        # 如果达到最大尝试次数仍未得到有效GFR，发出警告并继续尝试
        if not valid_gfr:
            warnings.warn(f"ID为 {person_id} 的个体，无法在 {max_attempts} 次尝试内生成符合范围的GFR。继续尝试...")
            
            # 继续尝试，直到得到符合范围的GFR
            while not valid_gfr:
                scr_umol_l = calculate_scr_umol_l(person_age, person_gender)
                scr_mg_dl = convert_scr_umol_l_to_mg_dl(scr_umol_l)
                
                egfr_cg = calculate_egfr_cg(person_age, person_weight, scr_mg_dl, person_gender)
                
                if min_gfr <= egfr_cg <= max_gfr:
                    valid_gfr = True
                    print(f"ID为 {person_id} 的个体，成功生成符合范围的GFR。")

        kidney_volume = calculate_kidney_volume(person_weight, person_height)
        
        protein_params = calculate_kidney_protein_parameters()
        kidney_weight = calculate_kidney_weight(kidney_volume, protein_params['Kidney_density_g_L'])
        
        # 使用传入的ethnicity参数（如果CSV中没有ethnicity列，此参数将作为默认值）
        current_ethnicity = row_demographics.get('Ethnicity', ethnicity)
        nephron_millions = calculate_nephron_number(kidney_weight, current_ethnicity, person_age)

        mech_kim_params = calculate_mech_kim_parameters()
        bladder_flow = get_bladder_flow()
        proximal_tubule_cells = calculate_proximal_tubule_cells()
        blood_bypass = calculate_blood_bypass_parameters()
        filtration_model = calculate_mechanistic_filtration_parameters()

        # --- 整理当前个体数据 ---
        current_row_data = {
            'ID': person_id,
            'Distribution': person_distribution,
            'Gender': person_gender, 
            'Age_years': person_age,
            'Weight_kg': person_weight,
            'Height_cm': person_height,
            'BSA_m2': person_bsa, 
            'Scr_plasma_umol_L': scr_umol_l,
            'Scr_plasma_mg_dL': scr_mg_dl,
            'GFR_kidney_CG_mL_min': egfr_cg,
            'GFR_kidney_MDRD_mL_min': calculate_egfr_mdrd(person_age, scr_mg_dl, person_gender), # 保留MDRD计算
            'Volume_kidney_mL': kidney_volume,
            'Weight_kidney_g': kidney_weight,
            'Count_nephron_kidney_millions': nephron_millions,
            'Flow_bladder_mL_min': bladder_flow,
            'Density_cell_kidney_proximal_tubule_millions_g': proximal_tubule_cells,
            # 蛋白参数
            'Content_protein_kidney_S9_mg_g': protein_params['S9_protein_mg_g'],
            'Content_protein_kidney_microsomal_mg_g': protein_params['Microsomal_protein_mg_g'],
            'Content_protein_kidney_cytosolic_mg_g': protein_params['Cytosolic_protein_mg_g'],
            'Density_kidney_g_L': protein_params['Kidney_density_g_L'], 
            # Mech Kim参数
            'Permeability_kidney': mech_kim_params['permeability'],
            'Surface_area_kidney_cm2': mech_kim_params['surface_area'],
            'Parameter_kidney_other': mech_kim_params['other_param'],
            'Ratio_kidney_cortex_medulla': mech_kim_params['Cortex_Medulla_Ratio'],
            'Percent_kidney_peritubular_capillaries': mech_kim_params['Peritubular_Capillaries_Percent_Kidney_Volume'],
            # 血液分流
            'Percent_blood_kidney_bypass1': blood_bypass['bypass1_percent'],
            'Percent_blood_kidney_bypass2': blood_bypass['bypass2_percent'],
            # 机械过滤模型参数
            'Jv_s_kidney_glomerulus': filtration_model['filtration_fractions']['jv_s'],
            'Jv_l_kidney_glomerulus': filtration_model['filtration_fractions']['jv_l'],
            'Alpha_s_kidney_glomerulus': filtration_model['conductance_fractions']['alpha_s'],
            'Alpha_l_kidney_glomerulus': filtration_model['conductance_fractions']['alpha_l'],
            'Ratio_ns_nl_kidney_glomerulus': filtration_model['pore_parameters']['ns_nl_ratio'],
            'Radius_pore_s_kidney_glomerulus_nm': filtration_model['pore_parameters']['r_pore_s_nm'],
            'Radius_pore_l_kidney_glomerulus_nm': filtration_model['pore_parameters']['r_pore_l_nm'],
            'Pressure_delta_p_kidney_glomerulus_mmHg': filtration_model['pressure_parameters']['delta_p_mmHg'],
            'Pressure_osmotic_plasma_kidney_glomerulus_mmHg': filtration_model['pressure_parameters']['plasma_osmotic_pressure_mmHg'],
            'Pressure_delta_pi_kidney_glomerulus_mmHg': filtration_model['pressure_parameters']['delta_pi_mmHg'],
            'Pressure_filtration_net_kidney_glomerulus_mmHg': filtration_model['pressure_parameters']['net_filtration_pressure_mmHg'],
        }

        # 添加肾单位体积和尺寸信息
        for seg, v in nephron_volumes.items():
            if seg == 'total':
                current_row_data[f'Volume_nephron_total_mL'] = v
            else:
                current_row_data[f'Volume_nephron_{seg}_mL'] = v
                
        for segment, dims in nephron_dimensions.items():
            current_row_data[f'Length_nephron_{segment}_mm'] = dims['length_mm']
            current_row_data[f'Diameter_nephron_{segment}_mm'] = dims['diameter_mm']

        processed_data.append(current_row_data)

    # 将处理后的数据转换为DataFrame并保存到CSV
    df_output = pd.DataFrame(processed_data)
    df_output.to_csv(output_save_path, index=False)
    print(f"已成功保存所有肾脏参数到: {output_save_path}")

    # 额外输出肾体积
    if 'ID' in df_output.columns and 'Volume_kidney_mL' in df_output.columns:
        kidney_volume_df = df_output[['ID', 'Volume_kidney_mL']]
        kidney_volume_df.to_csv('kidney_volume.csv', index=False)
        print("已输出肾体积到 kidney_volume.csv")

def generate_kidney_parameters_from_df(
    df_demographics,
    ethnicity='caucasian',
    min_gfr=30,
    max_gfr=400
):
    """
    直接接受人口学DataFrame，批量生成肾脏参数，返回DataFrame。
    """
    import numpy as np
    import pandas as pd
    import warnings
    processed_data = []
    nephron_dimensions = calculate_nephron_dimensions()
    nephron_volumes = calculate_nephron_volume(nephron_dimensions)
    for index, row_demographics in df_demographics.iterrows():
        person_id = row_demographics.get('id', index)
        person_gender = row_demographics.get('gender', 'male').capitalize()
        person_age = row_demographics.get('age')
        person_weight = row_demographics.get('weight')
        person_height = row_demographics.get('height')
        person_bsa = row_demographics.get('bsa', np.nan)
        if pd.isna(person_age) or pd.isna(person_weight) or pd.isna(person_height):
            warnings.warn(f"跳过ID为 {person_id} 的个体，因年龄、体重或身高数据缺失。")
            continue
        valid_gfr = False
        attempts = 0
        max_attempts = 10
        while not valid_gfr and attempts < max_attempts:
            scr_umol_l = calculate_scr_umol_l(person_age, person_gender)
            scr_mg_dl = convert_scr_umol_l_to_mg_dl(scr_umol_l)
            egfr_cg = calculate_egfr_cg(person_age, person_weight, scr_mg_dl, person_gender)
            # 只用CG公式判断
            if min_gfr <= egfr_cg <= max_gfr:
                valid_gfr = True
            else:
                attempts += 1
        if not valid_gfr:
            warnings.warn(f"ID为 {person_id} 的个体，无法在 {max_attempts} 次尝试内生成符合范围的GFR。继续尝试...")
            while not valid_gfr:
                scr_umol_l = calculate_scr_umol_l(person_age, person_gender)
                scr_mg_dl = convert_scr_umol_l_to_mg_dl(scr_umol_l)
                egfr_cg = calculate_egfr_cg(person_age, person_weight, scr_mg_dl, person_gender)
                if min_gfr <= egfr_cg <= max_gfr:
                    valid_gfr = True
        kidney_volume = calculate_kidney_volume(person_weight, person_height)
        protein_params = calculate_kidney_protein_parameters()
        kidney_weight = calculate_kidney_weight(kidney_volume, protein_params['Kidney_density_g_L'])
        current_ethnicity = row_demographics.get('ethnicity', ethnicity)
        nephron_millions = calculate_nephron_number(kidney_weight, current_ethnicity, person_age)
        mech_kim_params = calculate_mech_kim_parameters()
        bladder_flow = get_bladder_flow()
        proximal_tubule_cells = calculate_proximal_tubule_cells()
        blood_bypass = calculate_blood_bypass_parameters()
        filtration_model = calculate_mechanistic_filtration_parameters()
        current_row_data = {
            'id': person_id,
            'gender': person_gender,
            'age': person_age,
            'weight': person_weight,
            'height': person_height,
            'bsa': person_bsa,
            'Scr_plasma_umol_L': scr_umol_l,
            'Scr_plasma_mg_dL': scr_mg_dl,
            'GFR_kidney_CG_mL_min': egfr_cg,
            'GFR_kidney_MDRD_mL_min': calculate_egfr_mdrd(person_age, scr_mg_dl, person_gender), # 保留MDRD计算
            'Volume_kidney_mL': kidney_volume,
            'Weight_kidney_g': kidney_weight,
            'Count_nephron_kidney_millions': nephron_millions,
            'Flow_bladder_mL_min': bladder_flow,
            'Density_cell_kidney_proximal_tubule_millions_g': proximal_tubule_cells,
            'Content_protein_kidney_S9_mg_g': protein_params['S9_protein_mg_g'],
            'Content_protein_kidney_microsomal_mg_g': protein_params['Microsomal_protein_mg_g'],
            'Content_protein_kidney_cytosolic_mg_g': protein_params['Cytosolic_protein_mg_g'],
            'Density_kidney_g_L': protein_params['Kidney_density_g_L'],
            'Permeability_kidney': mech_kim_params['permeability'],
            'Surface_area_kidney_cm2': mech_kim_params['surface_area'],
            'Parameter_kidney_other': mech_kim_params['other_param'],
            'Ratio_kidney_cortex_medulla': mech_kim_params['Cortex_Medulla_Ratio'],
            'Percent_kidney_peritubular_capillaries': mech_kim_params['Peritubular_Capillaries_Percent_Kidney_Volume'],
            'Percent_blood_kidney_bypass1': blood_bypass['bypass1_percent'],
            'Percent_blood_kidney_bypass2': blood_bypass['bypass2_percent'],
            'Jv_s_kidney_glomerulus': filtration_model['filtration_fractions']['jv_s'],
            'Jv_l_kidney_glomerulus': filtration_model['filtration_fractions']['jv_l'],
            'Alpha_s_kidney_glomerulus': filtration_model['conductance_fractions']['alpha_s'],
            'Alpha_l_kidney_glomerulus': filtration_model['conductance_fractions']['alpha_l'],
            'Ratio_ns_nl_kidney_glomerulus': filtration_model['pore_parameters']['ns_nl_ratio'],
            'Radius_pore_s_kidney_glomerulus_nm': filtration_model['pore_parameters']['r_pore_s_nm'],
            'Radius_pore_l_kidney_glomerulus_nm': filtration_model['pore_parameters']['r_pore_l_nm'],
            'Pressure_delta_p_kidney_glomerulus_mmHg': filtration_model['pressure_parameters']['delta_p_mmHg'],
            'Pressure_osmotic_plasma_kidney_glomerulus_mmHg': filtration_model['pressure_parameters']['plasma_osmotic_pressure_mmHg'],
            'Pressure_delta_pi_kidney_glomerulus_mmHg': filtration_model['pressure_parameters']['delta_pi_mmHg'],
            'Pressure_filtration_net_kidney_glomerulus_mmHg': filtration_model['pressure_parameters']['net_filtration_pressure_mmHg'],
        }
        for seg, v in nephron_volumes.items():
            if seg == 'total':
                current_row_data[f'Volume_nephron_total_mL'] = v
            else:
                current_row_data[f'Volume_nephron_{seg}_mL'] = v
        for segment, dims in nephron_dimensions.items():
            current_row_data[f'Length_nephron_{segment}_mm'] = dims['length_mm']
            current_row_data[f'Diameter_nephron_{segment}_mm'] = dims['diameter_mm']
        processed_data.append(current_row_data)
    df_output = pd.DataFrame(processed_data)
    return df_output

# ====================================================================================================
# V. 主程序入口 (Main Execution Block)
# ====================================================================================================

if __name__ == "__main__":
    import pandas as pd
    # 构造测试数据
    test_df = pd.DataFrame({
        'id': [1, 2],
        'age': [30, 40],
        'weight': [70, 65],
        'height': [175, 160]
    })
    result = generate_kidney_parameters_from_df(test_df)
    print(result)


def clean_kidney_parameter_name(name):
    """清理Kidney参数名称，移除特殊字符"""
    import re
    return re.sub(r'[^a-zA-Z0-9]', '', str(name))


def clean_kidney_transporter_name(name):
    """清理Kidney转运体名称，保留括号但移除其他特殊字符"""
    import re
    # 保留括号、字母、数字，移除其他特殊字符
    return re.sub(r'[^a-zA-Z0-9()]', '', str(name))


def sample_lognormal_kidney(mean, cv, size=1):
    """从对数正态分布采样（Kidney模块专用）"""
    import numpy as np
    if mean <= 0:
        return np.zeros(size)
    sigma_log = np.sqrt(np.log(1 + (cv/100)**2))
    mu_log = np.log(mean) - 0.5 * sigma_log**2
    return np.exp(np.random.normal(loc=mu_log, scale=sigma_log, size=size))


def generate_kidney_transporter_genotypes_and_phenotypes(pop_df, random_seed=42):
    """
    生成Kidney转运体基因型和表型数据
    
    参数:
    pop_df: 包含id的人口统计学DataFrame
    random_seed: 随机种子
    
    返回:
    包含Kidney转运体基因型和表型的DataFrame
    """
    import numpy as np
    import pandas as pd
    
    np.random.seed(random_seed)
    n_subjects = len(pop_df)
    results = {}
    results['id'] = pop_df['id'].values
    
    # 为每个Kidney转运体生成基因型和表型
    for transporter_name in KIDNEY_TRANSPORTER_FREQUENCIES.keys():
        frequencies = KIDNEY_TRANSPORTER_FREQUENCIES[transporter_name]
        abundances = KIDNEY_TRANSPORTER_ABUNDANCES[transporter_name]
        
        # 生成基因型
        phenotypes = list(frequencies.keys())
        phenotype_probs = list(frequencies.values())
        
        # 确保概率和为1
        total_prob = sum(phenotype_probs)
        if total_prob > 0:
            phenotype_probs = [p/total_prob for p in phenotype_probs]
        else:
            phenotype_probs = [1.0] + [0.0] * (len(phenotypes) - 1)
        
        # 为每个人分配基因型
        genotypes = np.random.choice(phenotypes, size=n_subjects, p=phenotype_probs)
        
        # 生成对应的表型数据
        abundances_values = []
        turnover_values = []
        
        for i, genotype in enumerate(genotypes):
            # 获取该基因型的丰度参数
            abundance_params = abundances[genotype]
            mean_abundance = abundance_params['mean']
            cv_abundance = abundance_params['cv']
            
            # 生成丰度值
            if mean_abundance > 0:
                abundance = sample_lognormal_kidney(mean_abundance, cv_abundance, 1)[0]
            else:
                abundance = 0.0
            
            abundances_values.append(abundance)
            
            # 生成周转时间（所有人使用相同的周转参数）
            if i == 0:  # 只在第一次计算周转时间
                turnover_mean = abundances['turnover_mean']
                turnover_cv = abundances['turnover_cv']
                turnover = sample_lognormal_kidney(turnover_mean, turnover_cv, 1)[0]
                turnover_values = [turnover] * n_subjects
        
        # 存储结果
        clean_transporter = clean_kidney_transporter_name(transporter_name)
        results[f'Kidney_{clean_transporter}_genotype'] = genotypes
        results[f'Kidney_{clean_transporter}_abundance_pmol_mg'] = abundances_values
        results[f'Kidney_{clean_transporter}_turnover_1_h'] = turnover_values
    
    return pd.DataFrame(results)


def generate_kidney_transporters_from_df(pop_df, random_seed=42):
    """
    生成Kidney转运体参数的主函数
    
    参数:
    pop_df: 包含id的人口统计学DataFrame
    random_seed: 随机种子
    
    返回:
    包含Kidney转运体参数的DataFrame
    """
    # 生成Kidney转运体数据
    kidney_transporter_df = generate_kidney_transporter_genotypes_and_phenotypes(pop_df, random_seed)
    
    return kidney_transporter_df

